﻿using System;
using Autofac;
using Jaeger;
using Jaeger.Reporters;
using Jaeger.Samplers;
using Jaeger.Senders;
using Jaeger.Senders.Thrift;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenTracing;
using OpenTracing.Util;
using Solution.Application.Behaviors;
using Solution.Application.Modules;

namespace Solution.Application.Extensions
{
    public static class OpenTraceExtensions
    {
        public static void AddOpenTracing(this IServiceCollection services, JaegerOptions options)
        {
            services.AddOpenTracing(builder =>
            {
                builder.AddEntityFrameworkCore();
                builder.AddLoggerProvider();
                builder.AddAspNetCore(options =>
                {
                    options.Hosting.OperationNameResolver = (context) =>
                    {
                        return context.Request.Path.ToUriComponent();
                    };
                    options.Hosting.IgnorePatterns.Add(ctx => ctx.Request.Path == "/health");
                });
            });

            services.AddSingleton<ITracer>(serviceProvider =>
            {
                var serviceName = options.ServiceName;
                if (string.IsNullOrEmpty(serviceName))
                {
                    serviceName = "Solution.WebHost";
                }

                var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
                // This is necessary to pick the correct sender, otherwise a NoopSender is used!
                Configuration.SenderConfiguration.DefaultSenderResolver = new SenderResolver(loggerFactory)
                    .RegisterSenderFactory<ThriftSenderFactory>();

                var reporter = new RemoteReporter.Builder()
                .WithLoggerFactory(loggerFactory)
                .WithSender(new UdpSender(options.AgentHost, 6831, 0))
                .Build();

                // This will log to a default localhost installation of Jaeger.
                var tracer = new Tracer.Builder(serviceName)
                    .WithLoggerFactory(loggerFactory)
                    .WithSampler(new ConstSampler(true))
                    .WithReporter(reporter)
                    .Build();

                // Allows code that can't use DI to also access the tracer.
                if (!GlobalTracer.IsRegistered())
                {
                    GlobalTracer.Register(tracer);
                }

                return tracer;
            });
        }

        public static void AddPipelineBehaviors(this ContainerBuilder builder)
        {
            builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
        }
    }
}